﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.Generic;
using System.IO;
using System.Windows.Media.Imaging;
using System.Text;
using System.Linq;
using System.Collections.ObjectModel;
using System.Windows.Browser;

namespace FilesUploader.Model
{
    [ScriptableType]
    public class UploaderModel
    {
        //public event EventHandler UploadPhotoCompleted;

        public UploaderModel()
        {
            Photos = new ObservableCollection<Photo>();
            Mess = "giorno";
        }

        public ObservableCollection<Photo> Photos { get; set; }

        internal void AsyncUpload(System.Collections.Generic.IEnumerable<System.IO.FileInfo> iEnumerable, Uri uriPhotos, string destFolder, string notifyTo)
        {
            _uriPhotos = uriPhotos;
            _uriRestService = notifyTo;
            _destFolder = destFolder;
            foreach (var item in iEnumerable)
            {
                Photos.Add(new Photo()
                {
                    PhotoName = item.Name,
                    File = item,
                    Extension = item.Extension,
                    PhotoBase64 = String.Format("{0}|{1}", destFolder, item.Name),
                    UploadState = UploadState.New
                });
            }
            Upload();
        }

        private void Upload()
        {
            foreach (var item in Photos.Where(p => p.UploadState == UploadState.New))
            {
                UploadFotoDipendenteAsync(item);
            }
        }

        int chunkSize = 262144;

        public void UploadFotoDipendenteAsync(Photo photo)
        {
            WebClient client = new WebClient();
            client.AllowReadStreamBuffering = true;

            client.UploadStringCompleted += (sender, e) =>
            {
                if (e.Error == null)
                {
                    if (photo.CurrentChunk < photo.NumberOfChunks)
                    {
                        SendChunk(photo, client);
                    }
                    else if (photo.CurrentChunk == photo.NumberOfChunks)
                    {
                        SendLastChunk(photo, client);
                    }
                    else
                    {
                        if (!String.IsNullOrEmpty(_uriRestService))
                        {
                            NotifyUploadCompleted(photo);
                        }
                        else
                        {
                            DownloadStringCompleted(photo);
                        }
                    }
                    photo.Percentage = (int)(photo.CurrentChunk * 100 / photo.NumberOfChunks);
                }
                else if (photo.Retries < 3)
                {
                    photo.CurrentChunk -= 1;
                    photo.Retries += 1;
                    SendChunk(photo, client);
                }
                else
                {
                    DownloadStringCompletedError(photo);
                }
            };

            SendFirstChunk(photo, client);
        }

        private void SendFirstChunk(Photo photo, WebClient client)
        {
            Stream f = photo.File.OpenRead();
            byte[] bs = new byte[chunkSize];
            f.Read(bs, 0, chunkSize);
            CalculateChunkNumber(photo, f.Length);
            photo.CurrentChunk += 1;
            //photo.Percentage = (int)(photo.CurrentChunk * 100 / photo.NumberOfChunks);
            client.UploadStringAsync(new Uri(String.Format("{0}?type=U", _uriPhotos)), "POST", String.Format("{0}|{1}", photo.PhotoBase64, Convert.ToBase64String(bs)), photo.PhotoName);
        }

        private void SendChunk(Photo photo, WebClient client)
        {
            Stream f2 = photo.File.OpenRead();
            byte[] bytes = new byte[chunkSize];
            f2.Seek(photo.CurrentChunk * chunkSize, SeekOrigin.Begin);
            int red = f2.Read(bytes, 0, chunkSize);
            photo.CurrentChunk += 1;
            //photo.Percentage = (int)(photo.CurrentChunk * 100 / photo.NumberOfChunks);
            client.UploadStringAsync(new Uri(String.Format("{0}?type=U", _uriPhotos)), "POST", String.Format("{0}|{1}", photo.PhotoBase64, Convert.ToBase64String(bytes, 0, red)), photo.PhotoName);
            f2.Close();
        }

        private void SendLastChunk(Photo photo, WebClient client)
        {
            photo.CurrentChunk += 1;
            client.UploadStringAsync(new Uri(String.Format("{0}?type=U", _uriPhotos)), "POST", String.Format("{0}|{1}|{2}", photo.PhotoBase64, "last", "last"), photo.PhotoName);
        }

        private void CalculateChunkNumber(Photo photo, long streamLength)
        {
            photo.NumberOfChunks = ((int)(streamLength / (long)chunkSize)) + 1;
        }

        void NotifyUploadCompleted(Photo photo)
        {
            WebClient client = new WebClient();
            client.DownloadStringCompleted += (sender, e) =>
            {
                if (e.Error != null)
                {
                    DownloadStringCompletedError(photo);
                }
                else
                {
                    DownloadStringCompleted(photo);
                }
            };
            client.DownloadStringAsync(new Uri(string.Format("{0}/fold/{1}/file/{2}/ext/{3}",
                _uriRestService, _destFolder,
                System.IO.Path.GetFileNameWithoutExtension(photo.PhotoName),
                System.IO.Path.GetExtension(photo.PhotoName).Remove(0, 1))));
        }

        void DownloadStringCompleted(Photo photo)
        {
            photo.UploadState = UploadState.Uploaded;
            //Photos.Remove(photo);
            if (Photos.Where(p => p.UploadState == UploadState.New).Count() == 0 && UploadFinished != null)
            {
                UploadFinished(this, new EventArgs());
            }
        }

        void DownloadStringCompletedError(Photo photo)
        {
            photo.UploadState = UploadState.Error;
        }

        #region Properties
        private String _mess;

        public String Mess
        {
            get { return _mess; }
            set
            {
                _mess = value;
                OnPropertyChanged("Mess");
            }
        }
        #endregion

        Uri _uriPhotos;
        string _uriRestService;

        [ScriptableMember]
        public event EventHandler UploadFinished;
        string _destFolder { get; set; }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion


    }

    [ScriptableType]
    public class CustomEventHandler : EventArgs
    {
        public string AlbumName { get; set; }
    }
}
